import datetime
import inspect

from apscheduler.schedulers.tornado import TornadoScheduler
from mg_app_framework import InitFuncBasic, rabbitmq_get_subscribe_message_cache, get_organization_name, get_logger, \
    get_store, get_handler, TaskKey, update_context
from tornado import ioloop

from .db import collection_func_list
from .msg import rabbitmq_message_key_to_handler
from ..context_utils.context_utils import ContextUtils
from ..dao.container_mark_config_dao import ContainerMarkConfigDao
from ..models.container_config import ContainerMarkConfig


class InitFunc(InitFuncBasic):

    async def init_func(self):
        subscribe_message_cache = await rabbitmq_get_subscribe_message_cache()
        for key, msg in subscribe_message_cache.items():
            if key in rabbitmq_message_key_to_handler:
                await rabbitmq_message_key_to_handler[key](msg)

        await self.init_scheduler()
        await self.init_db()
        ioloop.IOLoop.current().call_later(3, callback=self.create_index)

        # await self.test_check()

        get_logger().info('--------------- init finished  ------------')

    async def test_check(self):
        from common_bind_service.test.common_test import test_all
        await test_all()

    async def init_db(self):
        """初始化默认的规则"""
        dao = ContainerMarkConfigDao()
        mark_config = await dao.get_all()
        if not mark_config:
            # 如果表名为空, 初始化默认的规则进去
            init_config = ContainerMarkConfig(container_name='烘烤托盘', max_count=480, prefix='JXLJ-L1', serial_len=3, end=999)
            init_config2 = ContainerMarkConfig(container_name='化成托盘', max_count=196, prefix='XESJ212408A', serial_len=5, end=99999)
            mark_config = [init_config, init_config2]
            await dao.insert_many(mark_config)
            get_logger().info('初始化, 插入托盘初始规则成功!')

        ContextUtils.set_container_mark_config(mark_config)
        get_logger().info('初始化托盘码值规则成功!')

    async def init_scheduler(self):
        get_logger().info('init_scheduler >>')
        scheduler = TornadoScheduler()
        # 定时任务重置流水号
        scheduler.add_job(self.clear_increment_serial_no, 'cron', hour=0, minute=0, second=0,
                          max_instances=1)

        scheduler.start()

    async def clear_increment_serial_no(self):
        # 0点清空缓存
        get_logger().info('clear_increment_serial_no >>')
        clear_key_type = [0, 1, 2]
        for key_type in clear_key_type:
            key = f'wip_type_{key_type}'
            update_context(key, 0)

    async def create_index(self):
        """自动创建索引"""
        from typing_extensions import TypedDict
        from typing import List, Dict
        class MongoIndexEntity(TypedDict):
            ns: str  # 表名
            v: int
            key: List[List[str]]  # [["_id", 1]] 索引状况
            background: bool  # 是否是背后建立索引

        MongoInformationEntity = Dict[str, MongoIndexEntity]  # key是索引名字

        # 为所有collection创建索引
        handler = get_handler(TaskKey.idi_server)
        database_collections_dict = {}
        for collection_func in collection_func_list:
            if inspect.iscoroutinefunction(collection_func):
                database_name, collection_name, index_list = await collection_func()
            else:
                database_name, collection_name, index_list = collection_func()
            if not index_list:
                continue
            if database_name in database_collections_dict:
                collection_list = database_collections_dict[database_name]
            else:
                collection_list = await handler[database_name].list_collection_names()
                database_collections_dict[database_name] = collection_list

            not_exists = False
            if collection_name not in collection_list:
                # 如果数据库不存在表, 则创建空表
                await handler[database_name].create_collection(collection_name)
                not_exists = True
            collection = handler[database_name][collection_name]

            # 对比已经存在的表的索引
            index_information: MongoInformationEntity = await handler[database_name][
                collection_name].index_information()

            def is_index_exist(index_keys):
                """
                检查索引是否已经存在, 防止重复创建
                可以根据索引名字来进行判断, 但是为了更准确, 还是遍历所有索引的key来进行判断是否存在
                """
                if not index_information or not_exists:
                    return False
                for index_name in index_information:
                    # 检查每个
                    db_index_keys = index_information[index_name]['key']
                    if len(db_index_keys) == len(index_keys):
                        _exists = True
                        for left_key_pair, right_key_pair in zip(db_index_keys, index_keys):
                            if left_key_pair[0] != right_key_pair[0] or left_key_pair[1] != right_key_pair[1]:
                                _exists = False
                                break
                        if _exists:
                            return True
                return False

            has_create_index = False
            for item in index_list:
                if isinstance(item, list):
                    if isinstance(item[-1], dict):
                        if not is_index_exist(item[:-1]):
                            await collection.create_index(item[:-1], **item[-1])
                            has_create_index = True
                    else:
                        if not is_index_exist(item):
                            await collection.create_index(item)
                            has_create_index = True
                else:
                    if len(item) == 3:
                        # 第三个参数是字典, 并且是创建索引额外的参数.
                        if not is_index_exist([(item[0], item[1])]):
                            await collection.create_index([(item[0], item[1])], **item[2])
                            has_create_index = True
                    elif len(item) == 2:
                        if not is_index_exist([item]):
                            await collection.create_index([item])
                            has_create_index = True
            if has_create_index:
                get_logger().info('handler[%s][%s] create index success' % (database_name, collection_name))
            else:
                get_logger().info('handler[%s][%s] index exists' % (database_name, collection_name))